﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Autofac;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using QQ2564874169.RelationalSql;
using QQ2564874169.RelationalSql.Trigger;
using QQ2564874169.TypeContainer.Autofac;
using Tests.RelationalSql.Trigger.Mocks;

namespace Tests.RelationalSql.Trigger
{
    [TestClass]
    public class 从数据库中读取触发内容
    {
        [TestMethod]
        public void 触发几个读取几个()
        {
            var cb = new ContainerBuilder();
            cb.RegisterType<MockSql>().AsImplementedInterfaces().InstancePerLifetimeScope();
            cb.RegisterType<MockDbExecute>().AsImplementedInterfaces();
            cb.RegisterType<TriggerPublisher>().AsSelf();
            var m_container = new AutofacContainer(cb.Build().BeginLifetimeScope());

            TriggerItem.CreateSchema(new MockSchemaCreater());
            var count = 0;
            var monitor = new DbExecuteMonitor(m_container);
            monitor.LoadService(typeof(TriggerPublisher));
            monitor.Start();

            var items = new List<TriggerItem>();

            DbExecute.Created += execute =>
            {
                execute.Before += (s, e) =>
                {
                    if (e.TableType == typeof(TriggerItem))
                        items.Add(e.Model as TriggerItem);
                };
            };

            using (var sql = new MockSql())
            {
                using (var execute = new MockDbExecute(sql))
                {
                    execute.Insert(new TestEntity {Id = 1, Name = "2", CreateTime = DateTime.Now, Result = 1});
                    execute.Update(new TestEntity2 {Name = "5", Id = 1, Result = 1});
                    execute.Delete(new TestEntity3 {Name = "10", Id = 1, Result = 1});
                }
            }
            monitor.Close();

            var t_container = new TriggerContainer();
            t_container.OnResolve += t =>
            {
                if (t != typeof(ISql))
                    return null;
                var sql = new MockSql();
                sql.Before += (s, e) =>
                {
                    var ssql = (ISql) s;

                    if (e.Context.Command.ToLower().Contains("select"))
                    {
                        if (items.Count < 1)
                        {
                            e.Result = new[] {new TriggerItem()};
                        }
                        else
                        {
                            e.Result = new[] {items.First()};
                            ssql.Data.Add("item", items.First());
                            items.RemoveAt(0);
                        }
                    }
                    else if (e.Context.Command.ToLower().Contains("update"))
                    {
                        e.Result = 1;
                    }
                };
                sql.TransactionAfter += (s, e) =>
                {
                    var ssql = (ISql) s;
                    if (e.IsCommited == false && ssql.Data.Contains("item"))
                    {
                        items.Add((TriggerItem) ssql.Data["item"]);
                    }
                    if (ssql.Data.Contains("item"))
                    {
                        ssql.Data.Remove("item");
                    }
                };
                return sql;
            };
            var types = new List<string>
            {
                typeof(TestEntity).AssemblyQualifiedName,
                typeof(TestEntity2).AssemblyQualifiedName,
                typeof(TestEntity3).AssemblyQualifiedName,
                typeof(UpdateArgs).AssemblyQualifiedName
            };
            var subcr = new TriggerSubscriber(t_container);
            subcr.Receive += (s, e) =>
            {
                if (types.Contains(e.Item.EntityType))
                {
                    types.Remove(e.Item.EntityType);
                    if (e.Item.Type == TriggerType.Update)
                    {
                        types.Remove(typeof(TestEntity2).AssemblyQualifiedName);
                    }
                    count++;
                }
            };
            subcr.Start(1);
            var time = DateTime.Now;
            while (items.Count > 0 && time.AddSeconds(3) > DateTime.Now)
            {
                Task.Delay(1000).Wait();
            }
            subcr.Stop();
            Assert.AreEqual(3, count);
        }
    }
}
